package com.treasure.mall.biz.service.core.community.impl;

import com.treasure.mall.biz.base.AbstractSearchableCrudService;
import com.treasure.mall.biz.base.SpecificationAndSort;
import com.treasure.mall.biz.dto.BaseSaveDTO;
import com.treasure.mall.biz.dto.BaseSearchDTO;
import com.treasure.mall.biz.dto.community.CommentsSearchCondition;
import com.treasure.mall.biz.entity.community.CommunityArticlePO;
import com.treasure.mall.biz.entity.community.CommunityCommentLikePO;
import com.treasure.mall.biz.entity.community.CommunityCommentPO;
import com.treasure.mall.biz.entity.community.CommunityCommentPO_;
import com.treasure.mall.biz.entity.user.UserPO;
import com.treasure.mall.biz.repository.community.CommunityCommentLikeRepository;
import com.treasure.mall.biz.repository.community.CommunityCommentRepository;
import com.treasure.mall.biz.service.core.community.CommunityArticleService;
import com.treasure.mall.biz.service.core.community.CommunityCommentService;
import com.treasure.mall.zbq.common.base.ApiResult;
import com.treasure.mall.zbq.common.base.ResultCodeEnum;
import com.treasure.mall.zbq.common.exception.ApiException;
import com.treasure.mall.zbq.common.ienum.community.CommunityEnums;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
@Slf4j
public class CommunityCommentServiceImpl extends AbstractSearchableCrudService<CommunityCommentPO, Long> implements CommunityCommentService {

    private CommunityCommentRepository communityCommentRepository;

    @Autowired
    private CommunityArticleService articleService;

    @Autowired
    private CommunityCommentLikeRepository commentLikeRepository;


    protected CommunityCommentServiceImpl(CommunityCommentRepository repository) {
        super(repository);
        this.communityCommentRepository = repository;
    }

    @Override
    protected SpecificationAndSort<CommunityCommentPO> specificationAndSort(BaseSearchDTO searchDTO) {
        CommentsSearchCondition condition = (CommentsSearchCondition) searchDTO;

        Specification<CommunityCommentPO> specification = (root, query, cb) -> {
            List<Predicate> predicates = new ArrayList<>();
            predicates.add(cb.equal(root.get(CommunityCommentPO_.commentsContentType), condition.commentsContentType()));

            if (condition.getArticleId() > 0) {
                predicates.add(cb.equal(root.get(CommunityCommentPO_.articleId), condition.getArticleId()));
            }

            predicates.add(cb.equal(root.get(CommunityCommentPO_.parentId), condition.getParentId()));

            return cb.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        Sort sort = new Sort(Sort.Direction.DESC, "createTime");

        return new SpecificationAndSort<>(specification, sort);
    }

    @Override
    public Map<String, CommunityCommentLikePO> findByUser(Long userId, List<CommunityCommentPO> pos) {
        List<Long> ids = pos.stream().map(CommunityCommentPO::getId).collect(Collectors.toList());

        List<CommunityCommentLikePO> likePOS = commentLikeRepository.findByUser_UserIdAndCommentIdIn(userId, ids);

        return likePOS.stream().collect(Collectors.toMap(CommunityCommentLikePO::commentKey, po -> po));
    }

    @Override
    @Transactional
    public CommunityCommentPO comment(long parentId, long rootId, CommunityArticlePO articlePO, String content, UserPO userPO) {
        CommunityCommentPO po = new CommunityCommentPO();
        po.setArticleId(articlePO.getId());
        po.setCommentsContentType(CommunityEnums.CommentsContentType.COMMUNITY_ARTICLE);
        po.setParentId(parentId);
        po.setRootId(rootId);
        po.setUserPO(userPO);

        if (articlePO.getAuthor().getId().equals(userPO.getId())) {
            po.setAuthor(true);
        }
        if (parentId > 0) {
            CommunityCommentPO parent = findById(parentId);
            po.setTargetUserId(parent.getUserPO().getUserId());
            po.setTargetUserName(parent.getUserPO().getNickName());
        } else {
            //target就是作者
            po.setTargetUserId(articlePO.getAuthor().getUserId());
            po.setTargetUserName(articlePO.getAuthor().getNickName());
        }
        po.setCommentsText(content);

        return save(po);
    }

    @Override
    @Transactional
    public CommunityCommentPO reply(Long commentId, String content, UserPO userPO) {
        CommunityCommentPO parent = findById(commentId);
        if (parent == null) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.BIZ_ERROR, "该评论不存在或已被删除"));
        }
        CommunityArticlePO articlePO = articleService.findById(parent.getArticleId());
        if (articlePO == null || articlePO.isDeleted()) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.ILLEGAL_STATE, "当前内容不存在或者内容已被删除"));
        }

        long rootId = parent.getRootId();
        if (rootId == 0) {
            rootId = parent.getId();
        }

        CommunityCommentPO po = comment(parent.getId(), rootId, articlePO, content, userPO);

        communityCommentRepository.updateReplyCount(parent.getId(), 1);

        return po;
    }

    @Override
    @Transactional
    public boolean likeToggle(long commentId, UserPO userPO) {
        if (!communityCommentRepository.existsById(commentId)) {
            throw new ApiException(ApiResult.errorWith(ResultCodeEnum.BIZ_ERROR, "该评论不存在或已被删除"));
        }

        CommunityCommentLikePO po = commentLikeRepository.findByUser_UserIdAndCommentId(userPO.getUserId(), commentId);
        if (po == null) {
            po = new CommunityCommentLikePO();
            po.setCommentId(commentId);
            po.setUser(userPO);

            commentLikeRepository.save(po);

            communityCommentRepository.updateLikeCount(commentId, 1);

            return true;
        } else {
            commentLikeRepository.deleteById(po.getId());

            communityCommentRepository.updateLikeCount(commentId, -1);

            return false;
        }
    }

    @Override
    public boolean isUserLiked(Long commentId, Long userId) {
        return commentLikeRepository.existsByUser_UserIdAndCommentId(userId, commentId);
    }

    @Override
    public CommunityCommentPO save(BaseSaveDTO saveDTO) {
        return null;
    }
}
